<?php
/**
* copyright: 2009-11-5@sina
* author:    yanbo4@staff.sina.com.cn
* desc:      BaseModelMemCache,Memcached is PHP defined class
*/
class BaseModelMemCached
{
	/*
	* The Memcache Server's system configure
	* @var string,eg:'host:port'
	*/
	private $_server  = NULL;
	/*
	* The Memcache Server's host
	* @var string
	*/
	private $_host = NULL;
	/*
	* The Memcache Server's port
	* @var unsigned integer
	*/
	private $_port = NULL;
	/*
	* The Memcache Server's connect timeout
	* @var unsigned integer,system default is 1 
	*/
	private $_timeout = 1;
	/*
	* The Memcache Server's failed retry interval
	* @var unsigned integer,system default is 15
	*/
	private $_retry_interval = 15;
	/*
	* The Memcache Server should be considered online. 
	* @var boolean,system default is true
	*/
	private $_status  = true; 
	/*
	* The Memcache handler
	* @var object
	*/
	protected static $_mc = NULL;
	/*
	* The Memcache key default expire time
	* @var unsigned integer
	*/
	private $_expire  = 60;  //seconds
	/*
	* Constant attributes
	*/
	const ATTRUPDATE = 'mc_attributes_set';
	/*
	* @desc constructor
	* @access public
	* @param server string type
	* @param supperaddSvrs array object,store data like array("host:port",...,"host:port").
	* @param timeout unsigned integer type
	*/
	public function __construct($server=NULL,$supperaddSvrs=NULL,$timeout=NULL)
	{
		if( NULL !== $server ) {
			$this->_server = $server;
		}
		if( NULL !== $timeout ) {
			$this->_timeout = (int)$timeout;
		}
		if( NULL === self::$_mc) {
			$this->_connect();			
			if( NULL !== $supperaddSvrs ) {
				for( $i = 0, $len = count($supperaddSvrs); $i < $len; $i++ ) {
					//0->host,1->port
					$_list = explode(":",$supperaddSvrs[$i]);
					$this->addServer($_list[0],$_list[1]);
				}
			}
		}
	}
	/*
	* @access public method
	* @describle get key's value
	* @param key string type
	* @return the retrieve item from the server
	*/
	public function get($key)
	{
		return self::$_mc->get($key);
	}
	/*
	* @access public method
	* @describle set key's value
	* @param key string type
	* @param value mix type
	* @param expire unsigned integer, meanning the item value expired time,seconds
	* @param compressed emun(0,MEMCACHE_COMPRESSED),default is 0
	* @return true on success or false on failure
	*/
	public function set($key,$value,$expire=NULL,$compressed=0)
	{
		if( is_array($value) && $value[BaseModelMemCached::ATTRUPDATE] == 1 ) {
			$_data = self::$_mc->get($key);
			if( FALSE === $_data ) {
				return TRUE;
			}
			foreach( $value as $_key => $_value ) {
				if( $_key == MemCachedU::ATTRUPDATE ) {
					continue;
				}
				$_data[$_key] = $_value;
			}
			$_data[MCC::REALKEY] = time();
			$value = &$_data;
		}
		return self::$_mc->set($key,$value,$this->_getRegularCompress($compressed),$this->_getRegularExpire($expire));
	}
	/*
	* @access public method
	* @describle add key's value
	* @param key string type
	* @param value mix type
	* @param expire unsigned integer, meanning the item value expired time,seconds
	* @param compressed emun(0,MEMCACHE_COMPRESSED),default is 0
	* @return true on success or false on failure
	*/
	public function add($key,$value,$expire=NULL,$compressed=0)
	{
		return self::$_mc->add($key,$value,$this->_getRegularCompress($compressed),$this->_getRegularExpire($expire));
	}
	/*
	* @access public method
	* @describle update key's value
	* @param key string type
	* @param value mix type
	* @param expire unsigned integer, meanning the item value expired time,seconds
	* @param compressed emun(0,MEMCACHE_COMPRESSED),default is 0
	* @return true on success or false on failure
	*/
	public function update($key,$value,$expire=NULL,$compressed=0)
	{
		return $this->replace($key,$value,$expire,$compressed);
	}
	/*
	* @access public method
	* @describle replace key's value
	* @param key string type
	* @param value mix type
	* @param expire unsigned integer, meanning the item value expired time,seconds
	* @param compressed emun(0,MEMCACHE_COMPRESSED),default is 0
	* @return true on success or false on failure
	*/
	public function replace($key,$value,$expire=NULL,$compressed=0)
	{
		return self::$_mc->replace($key,$value,$this->_getRegularCompress($compressed),$this->_getRegularExpire($expire));
	}
	/*
	* @access public method
	* @describle delete the key
	* @param key string type
	* @return true on success or false on failure
	*/
	public function delete($key)
	{
		return self::$_mc->delete($key);
	}
	/*
	* @access public method
	* @describle get the version of memcache
	* @returna string of server version number or false on failure
	*/
	public function getVersion()
	{
		return self::$_mc->getVersion();
	}
	/*
	* @access public method
	* @describle get memcache server statistics value
	* @return an associative array of server statistics or FALSE on failure
	*/
	public function getStats()
	{
		return self::$_mc->getStats();
	}
	/*
	* @access public method
	* @describle get statistics from all servers in pool
	* @return a two-dimensional associative array of server statistics or false on failure
	*/
	public function getExtendedStats()
	{
		return self::$_mc->getExtendedStats();
	}
	/*
	* @access public method
	* @describle get server status
	* @return a the servers status. 0 if server is failed, non-zero otherwise 
	*/
	public function getServerStatus()
	{
		return self::$_mc->getServerStatus($this->_host,$this->_port);
	}	
	/*
	* @access public method
	* @describle decrement key's value
	* @param key string type
	* @param value integer type,default is 1
	* @return false or the affected result (integer type)
	*/
	public function decrement($key,$value=1)
	{
		return self::$_mc->decrement($key,$value);
	}
	/*
	* @access public method
	* @describle increment key's value
	* @param key string type
	* @param value integer type,default is 1
	* @return false or the affected result (integer type)
	*/
	public function increment($key,$value=1)
	{
		return self::$_mc->increment($key,$value);
	}
	/*
	* @access public method
	* @describle close the memcache server
	* @return true on success or false on failure.
	*/
	public function close()
	{
		return self::$_mc->close();
	}
	/*
	* @access public method
	* @describle flush the memcache server
	* @return true on success or false on failure.
	*/
	public function flush()
	{
		return self::$_mc->flush();
	}
	/*
	* @access public method
	* @descible turn debug output on/off
	* @param flag boolean
	* @return true if PHP was built with --enable-debug option, otherwise returns false
	*/
	public function debug($flag)
	{
		return self::$_mc->debug($flag);
	}
	/*
	* @access public static method
	*/
	public static final function failureCallback($host,$port)
	{
		echo "MemCache Server Failed Connection.";
		echo "Server Information is {$host}:{$port}.";
	}
	/*
	* @access public static method
	*/
	public function addServer($host,$port)
	{
		return self::$_mc->addServer($host,$port);
	}
	/*
	* @access private method
	*/
	private function _serverConfig()
	{
		if( NULL === $this->_host ) {
			$_tmp = explode(":",$this->_server);
			$this->_host = $_tmp[0];
			$this->_port = $_tmp[1];
		}
	}
	/*
	* @access private method
	*/
	private function _connect()
	{
		$this->_serverConfig();
		self::$_mc = new Memcache;
		@self::$_mc->connect($this->_host,$this->_port,$this->_timeout);
		@memcache_set_server_params(self::$_mc,$this->_host,$this->_port,$this->_timeout,$this->_retry_interval,$this->_status,__CLASS__."::failureCallback");
	}
	/*
	* @access private method
	*/
	private function _getRegularExpire($expire)
	{
		return $expire !== NULL ? abs((int)$expire) : $this->_expire;
	}
	/*
	* @access private method
	*/
	private function _getRegularCompress($compressed)
	{
		return in_array($compressed,array(0,MEMCACHE_COMPRESSED)) ? $compressed : 0;
	}
}
?>